package com.fingard.dsp.bank.directbank.bony01;


import com.fingard.constant.Format;
import com.fingard.crypto.DigestHelper;
import com.fingard.dsp.bank.directbank.PaymentState;
import com.fingard.dsp.bank.directbank.bankInterface.IBatPayRec;
import com.fingard.dsp.bank.reqrespobj.batpayrec.ReqBatPayRec;
import com.fingard.dsp.bank.reqrespobj.batpayrec.ReqQryBatPayRec;
import com.fingard.dsp.bank.reqrespobj.batpayrec.RetAtsBatPayRec;
import com.fingard.dsp.bank.reqrespobj.batpayrec.RetAtsQryBatPayRec;
import com.fingard.dsp.bank.reqrespobj.batpayrec.detail.RetAtsBatPayRecDetail;
import com.fingard.io.FileHelper;
import com.fingard.net.ConnState;
import com.fingard.text.StringHelper;
import com.fingard.xml.XmlTextReader;
import com.fingard.xml.XmlTextWriter;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

public class BONY01BatPayRec extends BONY01Base implements IBatPayRec {

    /**
     * 批量代付-文件方式
     *
     * @param p_req1988
     * @return
     * @throws Exception
     */
    @Override
    public RetAtsBatPayRec d_1988_BatPay(ReqBatPayRec p_req1988) throws Exception {
        String busiType = "00";
        //目前暂时只支持本行
        RetAtsBatPayRec retAts = new RetAtsBatPayRec(p_req1988.reqHeader);
        transCode = "030003";
        try {

            //上传文件到sftp服务器
            Map<String, String> dataMap = uploadFile(p_req1988);
            //发送报文
            XmlTextWriter xmlWriter = new XmlTextWriter();
            writeCommonHeader(xmlWriter);
            xmlWriter.writeStartElement("Body");
            String batNo = Format.Date8Format.format(p_req1988.getPayDateOnly()) + convertBatNo(p_req1988.reqBatchNO);//8位日期+9位数字
            xmlWriter.writeElementString("BatNo", batNo);//批次号
            xmlWriter.writeElementString("PayAcctNo", p_req1988.ownAct);//付款人账号
            xmlWriter.writeElementString("PayAcctName", p_req1988.ownActName);//付款人名称
            xmlWriter.writeElementString("TotNum", p_req1988.totalNum);//总笔数
            xmlWriter.writeElementString("TotAmt", p_req1988.totalAmt);//总金额
            xmlWriter.writeElementString("BusiType", busiType);//业务类型
            xmlWriter.writeElementString("FileName", dataMap.get("FileName"));//提交文件名
            xmlWriter.writeElementString("MD5", dataMap.get("MD5"));//文件MD5
            xmlWriter.writeElementString("FileLen", dataMap.get("FileLen"));//文件大小
            xmlWriter.writeEndElement();
            xmlWriter.writeEndDocument();
            //发送银行前置
            String[] tmpStrRet = sendToBank(xmlWriter.toXmlString());
            //解析报文
            if (tmpStrRet[0].length() == 0) {
                StringBuilder tmpSbMsg = new StringBuilder();
                XmlTextReader tmpBkReader = loadBankRespXmlReader(tmpStrRet[1], tmpSbMsg);
                if (tmpBkReader != null) {
                    String retCode = tmpBkReader.getSimpleText("RespCode");
                    String respMsg = tmpBkReader.getSimpleText("RespMsg");
                    retAts.respCode = "0";
                    if (retCode != null && isActiveRetCode(retCode)) {
                        retAts.respInfo = respMsg;
                        retAts.transState = retCode;
                        retAts.payInfoCode = retAts.transState;
                        retAts.reqSeqID = p_req1988.reqBatchNO;
                        retAts.newReqSeqID = tmpBkReader.getFirstText("/Root/Body/BankBatNo");//银行批次号
                    } else {
                        retAts.respInfo = getBankConfig().getMapValueByKey("respCodeMapping", retCode);
                        retAts.transState = PaymentState.FAIL_Batch;
                        retAts.payInfoCode = retAts.transState;
                        retAts.reqSeqID = p_req1988.reqBatchNO;
                    }
                } else {
                    retAts.respCode = "-1";
                    retAts.respInfo = tmpSbMsg.toString();
                }
            } else if (tmpStrRet[0].equals(ConnState.FAIL)) {
                retAts.respCode = "0";
                retAts.respInfo = tmpStrRet[1];
                retAts.reqSeqID = p_req1988.reqBatchNO;
                retAts.transState = PaymentState.FAIL_Batch;
                retAts.payInfoCode = tmpStrRet[0];
            } else {
                retAts.respCode = "-1";
                retAts.respInfo = tmpStrRet[1];
            }
        } catch (Exception e) {
            if (e instanceof com.jcraft.jsch.JSchException) {
                retAts.respCode = "0";
                retAts.reqSeqID = p_req1988.reqBatchNO;
                retAts.transState = PaymentState.FAIL_Batch;
            } else {
                retAts.respCode = "-1";
            }
            retAts.respInfo = e.getMessage();
            e.printStackTrace();
        }
        if (retAts.respCode.equals("-1") && StringHelper.isNullOrEmpty(retAts.reqSeqID)) {
            retAts.reqSeqID = p_req1988.reqBatchNO;
        }
        retAts.writeRetToATS();
        return retAts;
    }

    /**
     * 批量代付批次结果查询
     *
     * @param p_req1998
     * @return
     * @throws Exception
     */
    @Override
    public RetAtsQryBatPayRec d_1998_QryBatPay(ReqQryBatPayRec p_req1998) throws Exception {
        //返回ats对象
        RetAtsQryBatPayRec retAts = new RetAtsQryBatPayRec(p_req1998.reqHeader);
        transCode = "010009";
        try {
            //写报文
            XmlTextWriter xmlWriter = new XmlTextWriter();
            writeCommonHeader(xmlWriter);
            xmlWriter.writeStartElement("Body");
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            String batNo = Format.Date8Format.format(sdf.parse(p_req1998.bgnDate)) + convertBatNo(p_req1998.reqBatchNO);
            xmlWriter.writeElementString("BatNo", batNo);//批次号
            xmlWriter.writeEndElement();
            xmlWriter.writeEndDocument();
            //发送银行前置机
            String[] tmpStrRet = sendToBank(xmlWriter.toXmlString());
            //赋值返回ats
            XmlTextReader tmpBkReader;
            if (tmpStrRet[0].length() == 0) {
                StringBuilder tmpSbMsg = new StringBuilder();
                tmpBkReader = loadBankRespXmlReader(tmpStrRet[1], tmpSbMsg);
                if (tmpBkReader != null) {
                    String retCode = tmpBkReader.getSimpleText("RespCode");
                    String respMsg = tmpBkReader.getSimpleText("RespMsg");
                    if (retCode != null && isActiveRetCode(retCode)) {
                        while (tmpBkReader.read("/Root/Body")) {
                            String batStat = tmpBkReader.readedXElement.getSingleText("BatStat");//处理状态 0-待处理 1-正在处理 2-处理完成
                            if (batStat.equals("2")) {
                                String fileName = tmpBkReader.readedXElement.getSingleText("FileName");//应答文件名
                                String MD5 = tmpBkReader.readedXElement.getSingleText("MD5");//文件MD5
                                String fileLen = tmpBkReader.readedXElement.getSingleText("FileLen");//文件大小
                                //下载文件
                                String fileText = downloadFile(fileName, fileLen, MD5);
                                String[] textLine = fileText.split("\n");
                                retAts.respInfo = respMsg;
                                retAts.respCode = "0";
                                retAts.transState = retCode + "+" + batStat;
                                retAts.payInfoCode = retAts.transState;
                                retAts.reqSeqID = fileName.replace(".txt", "").split("_")[2].substring(8);
                                retAts.writeBeforeDetail();
                                for (int i = 0; i < textLine.length; i++) {
                                    String[] textContent = textLine[i].split(":[|]:");
                                    RetAtsBatPayRecDetail tmpRetDetail = new RetAtsBatPayRecDetail();
                                    //序号
                                    //跨行标识
                                    //收款行号
                                    tmpRetDetail.recAct = textContent[3];//收款账号
                                    tmpRetDetail.recName = textContent[4];//收款户名
                                    tmpRetDetail.payAmount = textContent[5];//金额
                                    tmpRetDetail.memo = textContent[6];//摘要
                                    tmpRetDetail.result = textContent[7];//明细状态
                                    tmpRetDetail.usage = textContent[8];//返回描述
                                    tmpRetDetail.postScript = textContent[9];//备注 支付流水号
                                    retAts.writeRetDetail(tmpRetDetail);
                                }
                            } else {
                                retAts.transState = retCode + "+" + batStat;
                                retAts.payInfoCode = retAts.transState;
                                retAts.reqSeqID = p_req1998.reqBatchNO;
                                retAts.writeBeforeDetail();
                            }
                        }
                    } else {
                        retAts.respCode = "-1";
                        retAts.respInfo = getBankConfig().getMapValueByKey("respCodeMapping", retCode);
                    }
                } else {
                    retAts.respCode = "-1";
                    retAts.respInfo = tmpSbMsg.toString();
                }
            } else {
                retAts.respCode = "-1";
                retAts.respInfo = tmpStrRet[1];
            }
        } catch (Exception e) {
            retAts.respCode = "-1";
            retAts.respInfo = e.getMessage();
            e.printStackTrace();
        }
        if (retAts.respCode.equals("-1") && StringHelper.isNullOrEmpty(retAts.reqSeqID)) {
            retAts.reqSeqID = p_req1998.reqBatchNO;
        }
        if (retAts.respCode.equals("-1")) {
            retAts.writeBeforeDetail();
        }
        retAts.writeAfterDetail();
        return retAts;
    }

    @Override
    public RetAtsBatPayRec d_9188_BatPay(ReqBatPayRec p_req9188) throws Exception {
        return null;
    }

    @Override
    public RetAtsQryBatPayRec d_9198_QryBatPay(ReqQryBatPayRec p_req9198) throws Exception {
        return null;
    }


    /**
     * 上传文件
     *
     * @param p_req1988
     * @throws Exception
     */
    private Map<String, String> uploadFile(ReqBatPayRec p_req1988) throws Exception {
        Map<String, String> dataMap = new HashMap<String, String>();
        StringBuffer batStr = new StringBuffer();
        int count = 0;
        while (p_req1988.readRecord()) {
            batStr.append(++count).append(":|:");//序号:|:
            if (p_req1988.readedDetail.sameBnk.equals("1")) {//同行不需要输入收款行号
                batStr.append("1").append(":|:");
                batStr.append("").append(":|:");
            } else {
                batStr.append("2").append(":|:");
                batStr.append(p_req1988.readedDetail.recBankCode).append(":|:");//收款行号
            }
            batStr.append(p_req1988.readedDetail.recAct).append(":|:");//收款账号
            batStr.append(p_req1988.readedDetail.recName).append(":|:");//收款户名
            batStr.append(p_req1988.readedDetail.payAmount).append(":|:");//金额
            batStr.append(p_req1988.readedDetail.abstractATS).append(":|:");//摘要 对账码
            batStr.append(p_req1988.readedDetail.askNumber).append(":|:");//备注 支付流水号
            if (count < p_req1988.getTotalNum()) {
                batStr.append("\n");
            }
            if (count > 1000) {//文件明细笔数需控制上线，目前暂定最大1000笔
                break;
            }
        }
        String tmpBatStr = batStr.toString();
        String seqNo = Format.Date8Format.format(p_req1988.getPayDateTime()) + convertBatNo(p_req1988.reqBatchNO);//银行建议以8位日期+9位的序号组成
        String fileName = "REQ_" + bankFront.org + "_" + seqNo + ".txt";//银行规定文件名
        String md5 = DigestHelper.cryptoMD5RetHexStr(tmpBatStr.getBytes(getCharset())).toUpperCase();//获取md5摘要16进制
        InputStream is = new ByteArrayInputStream(tmpBatStr.getBytes(getCharset()));
        int fileLen = is.available();//上传字节长度
        Map<String, Object> jschMap = getChannel();

        //进行文件传输操作：put()、get()....
        ChannelSftp channel = (ChannelSftp) jschMap.get("channel");
        channel.put(is, fileName);//上传
        closeChannel((Session) jschMap.get("session"), (ChannelSftp) jschMap.get("channel"));
        if (is != null) {
            is.close();
        }

        dataMap.put("MD5", md5);
        dataMap.put("FileLen", String.valueOf(fileLen));
        dataMap.put("FileName", fileName);

        return dataMap;
    }

    /**
     * 下载文件
     *
     * @throws Exception
     */
    private String downloadFile(String fileName, String fileLen, String MD5) throws Exception {
        String src = getBankConfig().getMapValueByKey("connectConfig", "LOCALADDRESS");
        Map<String, Object> jschMap = getChannel();
        //进行文件传输操作：put()、get()....
        ChannelSftp channel = (ChannelSftp) jschMap.get("channel");
        channel.get(fileName, src);//下载
        closeChannel((Session) jschMap.get("session"), (ChannelSftp) jschMap.get("channel"));
        //文件校验（长度和md5摘要信息比对）
        File file = new File(src + "\\" + fileName);
        if (!fileLen.equals(String.valueOf(file.length()))) {
            throw new Exception("文件已损坏！");
        }
        byte[] tmpMD5 = DigestHelper.cryptoMD5FromFile(src + "\\" + fileName);
        if (!MD5.equals(StringHelper.bytesToHexString(tmpMD5).toUpperCase())) {
            throw new Exception("MD5校验不正确！文件已被修改！");
        }
        return FileHelper.readToString(file, getCharset());
    }

    private Map<String, Object> getChannel() throws Exception {
        Map<String, Object> jschMap = new HashMap<String, Object>();
        String ftpHost = getBankConfig().getMapValueByKey("connectConfig", "IP");
        String port = getBankConfig().getMapValueByKey("connectConfig", "PORT");
        String ftpUserName = getBankConfig().getMapValueByKey("connectConfig", "USERNAME");
        String ftpPassword = getBankConfig().getMapValueByKey("connectConfig", "PASSWORD");
        int timeout = Integer.parseInt(getBankConfig().getMapValueByKey("connectConfig", "TIMEOUT"));

        int ftpPort = 22;//如果没有设置则默认为22
        if (port != null || !port.equals("")) {
            ftpPort = Integer.parseInt(port);
        }
        //1、创建JSch类
        JSch jsch = new JSch();
        //2、创建本次的文件传输会话对象，并连接到SFTP服务器。
        Session session = jsch.getSession(ftpUserName, ftpHost, ftpPort); // 根据用户名，主机ip，端口获取一个Session对象
        if (ftpPassword != null) {
            session.setPassword(ftpPassword); // 设置密码
        }
        Properties config = new Properties();
        config.put("StrictHostKeyChecking", "no");
        session.setConfig(config); // 为Session对象设置properties
        session.setTimeout(timeout); // 设置timeout时间
        session.connect(); // 通过Session建立链接
        //3、在该session会话中开启一个SFTP通道，之后就可以在该通道中进行文件传输了
        ChannelSftp channelSftp = (ChannelSftp) session.openChannel("sftp");
        channelSftp.connect();
        jschMap.put("session", session);
        jschMap.put("channel", channelSftp);
        return jschMap;
    }

    private void closeChannel(Session session, ChannelSftp channel) throws Exception {
        if (channel != null) {
            channel.disconnect();
        }
        if (session != null) {
            session.disconnect();
        }
    }

    /**
     * 将批次号转化为9位序号
     *
     * @param batchNo
     * @return
     */
    private String convertBatNo(String batchNo) {
        char[] chars = batchNo.toCharArray();
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < chars.length; i++) {
            int num = chars[i];
            sb.append(num);
        }
        int len = sb.toString().length();
        return sb.toString().substring(len - 9, len);
    }

}
